﻿using HtmlAgilityPack;
using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Domain.WindAlert;
using Nop.Data;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;

namespace Nop.Services.WindAlert
{
    /// <summary>
    /// Winddata service
    /// </summary>
    public partial class ForecastDataService : IForecastDataService
    {
        #region Fields

        private readonly IRepository<ForecastData> _forecastDataRepository;
        private readonly IDbContext _dbContext;
        private readonly IWindHelpers _windHelper;
        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="windDataRepository">Live Station repository</param>
        public ForecastDataService(IRepository<ForecastData> forecastDataRepository
            ,IDbContext dbContext, IWindHelpers windHelper)
        {
            this._forecastDataRepository = forecastDataRepository;
            this._dbContext = dbContext;
            this._windHelper = windHelper;
        }
        #endregion

        #region Methods

        /// <summary>
        /// Clears a log
        /// </summary>
        public virtual void ClearAll()
        {
            var forecastData = _forecastDataRepository.Table.ToList();
            foreach (var wdItem in forecastData)
                _forecastDataRepository.Delete(wdItem);
            //setIdentity();
        }

        /// <summary>
        /// Deletes a forecastData
        /// </summary>
        /// <param name="windData">forecastData</param>
        public virtual void DeleteForecastData(ForecastData forecastData)
        {
            if (forecastData == null)
                throw new ArgumentNullException("forecastData");

            _forecastDataRepository.Delete(forecastData);
        }

        /// <summary>
        /// Gets all forecastDatas
        /// </summary>
        /// <returns>forecast data collection</returns>
        public virtual IList<ForecastData> GetAllForecastData(int spotId = 0)
        {
            var query = from m in _forecastDataRepository.Table
                            select m;
            if (spotId > 0)
                query = query.Where(fd => fd.SpotId == spotId);
            var forecastDatas = query.ToList();
            return forecastDatas;
        }

        /// <summary>
        /// Gets all forecastDatas
        /// </summary>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <returns>forecast data</returns>
        public virtual IPagedList<ForecastData> GetAllForecastData(int pageIndex, int pageSize, int spotId = 0)
        {
            var forecastDatas = GetAllForecastData(spotId);
            return new PagedList<ForecastData>(forecastDatas, pageIndex, pageSize);
        }


        /// <summary>
        /// Gets all forecastdata items
        /// </summary>
        /// <param name="fromUtc">fvdata item creation from; null to load all records</param>
        /// <param name="toUtc">forecastdata item creation to; null to load all records</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <returns>forecastdata item collection</returns>
        public virtual IPagedList<ForecastData> GetAllForecastData(DateTime? fromUtc, DateTime? toUtc, int pageIndex, int pageSize)
        {
            var query = _forecastDataRepository.Table;
            if (fromUtc.HasValue)
                query = query.Where(wd => fromUtc.Value <= wd.CreatedOnUtc);
            if (toUtc.HasValue)
                query = query.Where(wd => toUtc.Value >= wd.CreatedOnUtc);
            
            query = query.OrderByDescending(wd => wd.Id);
           // query = query.OrderByDescending(wd => wd.CreatedOnUtc);

            var forecastData = new PagedList<ForecastData>(query, pageIndex, pageSize);
            return forecastData;
        }

        /// <summary>
        /// Gets a forecastData
        /// </summary>
        /// <param name="forecastDataId">forecast data identifier</param>
        /// <returns>forecast data</returns>
        public virtual ForecastData GetForecastDataById(int forecastDataId)
        {
            if (forecastDataId == 0)
                return null;
            var forecastData = _forecastDataRepository.GetById(forecastDataId);
            return forecastData;
        }

        /// <summary>
        /// Get forecast data items by identifiers
        /// </summary>
        /// <param name="waveataIds">forecastdata item identifiers</param>
        /// <returns>forecastdata items</returns>
        public virtual IList<ForecastData> GetForecastDataByIds(int[] forecastDataIds)
        {
            if (forecastDataIds == null || forecastDataIds.Length == 0)
                return new List<ForecastData>();

            var query = from wd in _forecastDataRepository.Table
                        where forecastDataIds.Contains(wd.Id)
                        select wd;
            var forecastDataItems = query.ToList();
            //sort by passed identifiers
            var sortedForecastDataItems = new List<ForecastData>();
            foreach (int id in forecastDataIds)
            {
                var forecastData = forecastDataItems.Find(x => x.Id == id);
                if (forecastData != null)
                    sortedForecastDataItems.Add(forecastData);
            }
            return sortedForecastDataItems;
        }

        /// <summary>
        /// Get forecast data itemby spot Id
        /// </summary>
        /// <param name="SpotIds">spot identifiers</param>
        /// <returns>forecastdata items</returns>
        public virtual IList<ForecastData> GetForecastDataBySpotId(int spotId)
        {
            if (spotId < 1)
                return new List<ForecastData>();

            var query = from wd in _forecastDataRepository.Table
                        where wd.SpotId == spotId
                        select wd;

            var forecastDataItems = query.ToList();
            return forecastDataItems;
        }

        /// <summary>
        /// Get forecast data itemby spot Id and forecast name
        /// </summary>
        /// <param name="SpotIds">spot identifiers</param>
        /// <param name="name">name identifiers</param>
        /// <returns>forecastdata items</returns>
        public virtual ForecastData GetForecastDataBySpotIdAndName(int spotId, string name)
        {
            if (spotId < 1)
                return new ForecastData();

            var query = from fd in _forecastDataRepository.Table
                        where fd.SpotId == spotId && fd.Name == name
                        select fd;
            return query.FirstOrDefault() ;
        }

        /// <summary>
        /// Updates the forecast
        /// </summary>
        /// <param name="forecast">forecast</param>
        public virtual void UpdateForecastData(ForecastData forecastData)
        {
            if (forecastData == null)
                throw new ArgumentNullException("forecast");

            _forecastDataRepository.Update(forecastData);
       }


        /// <summary>
        /// Inserts a forecastData
        /// </summary>
        /// <param name="waveData">forecast data</param>
        public virtual void InsertForecastData(ForecastData forecastData)
        {
            if (forecastData == null)
                throw new ArgumentNullException("forecastData");

            _forecastDataRepository.Insert(forecastData);
        }


        /// <summary>
        /// Indicates whether a forecast exists
        /// </summary>
        /// <param name="forecastName">Forecast name</param>
        /// <returns>Result</returns>
        public virtual bool ForecastNameExists(string forecastName, int spotId)
        {
            if ( string.IsNullOrEmpty(forecastName))
                throw new ArgumentNullException("forecastName");
            var query = (from m in _forecastDataRepository.Table
                        where m.SpotId == spotId && m.Name == forecastName
                         select m).FirstOrDefault() ;

            if (query != null)
                return true;
            else
                return false;
        }


        #endregion

        #region update spot forecast

        public virtual string checkForecastDate()
        {
            var strAllData = _windHelper.GetPageData("http://isramar.ocean.org.il/isramar2009/wave_model/default.aspx?model=wam&region=fine");
            string strReturn = null;
            try
            {
                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(strAllData);
                HtmlNode.ElementsFlags.Remove("option");
                var nod = doc.DocumentNode.SelectSingleNode("//select[@id='ctl00_ContentPlaceHolder1_DateList']/option").OuterHtml;

                strReturn = Regex.Match(nod, @"\d+").Value;
                
            }
            catch (Exception ex)
            {
                string t = ex.Message;
            }
            return strReturn;
        }


        public virtual List<ForecastData> UpdateForecastSpot(Spot spot)
        {
            //view-source:http://isramar.ocean.org.il/isramar2009/wave_model/InfoLabel.aspx?x=32.1727&y=34.7978&model=wam&modeldate=1308040000&region=fine
            //get starting date
            int numberInt = 0;
            string isramarLastUpdatDate = checkForecastDate();
            Thread.CurrentThread.CurrentCulture = new CultureInfo("he-IL");
            int tempYear = (int.TryParse("20" + isramarLastUpdatDate.Substring(0, 2), out numberInt)) ? numberInt : 2010;
            int tempMonth = (int.TryParse(isramarLastUpdatDate.Substring(2, 2), out numberInt)) ? numberInt : 1;
            int tempDay = (int.TryParse(isramarLastUpdatDate.Substring(4, 2), out numberInt)) ? numberInt : 1;
            DateTime startingDate = new DateTime(tempYear, tempMonth, tempDay);

            string isramarUrl = string.Format("http://isramar.ocean.org.il/isramar2009/wave_model/InfoLabel.aspx?x={0}&y={1}&model=wam&modeldate={2}00&region=fine"
                                            , spot.lat, spot.lng, isramarLastUpdatDate);
            var strAllData = _windHelper.GetPageData(isramarUrl);
            
            var forecastDatas = new List<ForecastData>();
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(strAllData);

            for (int i = 0; i < 41; i++)
            {
                var forecastData = new ForecastData();
                double numberDouble = 0;
                forecastData.Name = "w" + i;
                try 
                {
                    List<List<string>> forecastWindData = doc.DocumentNode.SelectNodes("//table[@id='wnd" + i + "']")
                                   .Descendants("tr")
                                   .Skip(1)
                                   .Where(tr => tr.Elements("td").Count() > 1)
                                   .Select(tr => tr.Elements("td").Select(td => td.InnerText.Trim()).ToList())
                                   .ToList();
                    forecastData.WindSpeed = (double.TryParse(forecastWindData[1][1], out numberDouble)) ? numberDouble : 0;
                    forecastData.WindDirection = (int.TryParse(forecastWindData[2][1], out numberInt)) ? numberInt : 0;
                }
                catch 
                {
                    forecastData.WindSpeed = 0;
                    forecastData.WindDirection = 0;
                }
                try
                {
                    List<List<string>> forecastWaveData = doc.DocumentNode.SelectNodes("//table[@id='wav" + i + "']")
                                .Descendants("tr")
                                .Skip(1)
                                .Where(tr => tr.Elements("td").Count() > 1)
                                .Select(tr => tr.Elements("td").Select(td => td.InnerText.Trim()).ToList())
                                .ToList();

                    forecastData.Height = (double.TryParse(forecastWaveData[0][1], out numberDouble)) ? numberDouble : 0;
                    forecastData.WaveDirection = (int.TryParse(forecastWaveData[1][1], out numberInt)) ? numberInt : 0;
                    forecastData.Period = (double.TryParse(forecastWaveData[2][1], out numberDouble)) ? numberDouble : 0;
                }
                catch
                {
                      forecastData.Height =  0;
                      forecastData.WaveDirection = 0;
                        forecastData.Period =  0;
                }
                  
                forecastData.SpotId = spot.Id;
                forecastData.ForecastTime = startingDate.Date.Add(new TimeSpan((i * 3), 0, 0));
                forecastData.CreatedOnUtc = DateTime.Now;
                forecastDatas.Add(forecastData);
            }

            return forecastDatas;
        }
        #endregion 

    }
}
